#define __LIBRARY__            /*切记：这个一定要加，否则unistd.h中的宏无法使用，切记！*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "pthread.h"           /*包含自制的库文件，其中有系统调用API*/

#define COM_TIMES 1
#define COM_THREAD 2
#define COM_GO 3
#define COM_STATUS 4
#define COM_ABORT 5
#define COM_EXIT 6

struct com
{
	char string[20];
	int value;
	int number;
};

struct com command;

struct thread_args
{
	char* start_addr;
	int size;
	int times;
	int finished;
	int abort;
};

struct thread_args args[64]={};
pthread_t threads[64] = {};	
int fail = 0;

void* test_mem(void *thread_arg);
int get_command(void);

int main()
{
	int i,j,k;
	int first=0,second=0,third=0;
	int num_times = 0;
	int num_thread = 0;
	int size=0;
	void *value_ptr[64]={};
	char* start_addr = NULL;
	char* mem_addr = (char *)malloc(0x100000);   
	if(!mem_addr)
	{
		printf("Error:Memory is not enough!\n");
		exit(0);
	}

	while(1)
	{
		printf(">>>");
		fflush(stdout);
		get_command();
		switch (command.value)
		{
			case COM_TIMES:
				num_times = command.number;
				printf("Each byte will be tested by %d times.\n",num_times);
				first  = 1;
				continue;
			case COM_THREAD:
				num_thread = command.number;
				size = 0x100000 / num_thread;
				start_addr = mem_addr;
				for(i=0;i<num_thread;i++)       /*对线程参数进行初始化设置*/
			    {
					args[i].start_addr = start_addr;
					args[i].size = size;
					args[i].finished = 0;
					args[i].abort = 0;
					start_addr = start_addr + size;	
				}
				args[num_thread-1].size += (0x100000 % num_thread);
				printf("Will use %d threads.\n",num_thread);
				second = 1;
				continue;
			case COM_GO:
				if(first == 1 && second == 1)
			    {
					for(i=0;i<num_thread;i++)       /*对线程参数完成初始化，并且创建工作线程*/
					{
						args[i].finished = 0;
						args[i].times = num_times;
						pthread_create(&threads[i],NULL,(void *)test_mem,(void *)(&(args[i])));
					}
					third = 1;
					continue;
				}
				else
			    {
					printf("测试参数不完成，线程初始化未完成！\n");
					return -1;
				}
			case COM_STATUS:
				if(third == 1)
			    {
					for(i=0;i<num_thread;i++)
					{
						if(args[i].finished == args[i].size || args[i].abort == 1)
							printf("Thread %d has exited.(%08lX-%08lX, %d/%d)\n",i,(long)(args[i].start_addr-mem_addr),(long)(args[i].start_addr-mem_addr+args[i].size-1),args[i].finished,args[i].size);
						else if(args[i].finished > 0)
							printf("Thread %d is running.(%08lX-%08lX, %d/%d)\n",i,(long)(args[i].start_addr-mem_addr),(long)(args[i].start_addr-mem_addr+args[i].size-1),args[i].finished,args[i].size);
					}
					continue;
				}
				continue;
			case COM_ABORT:
				if(second == 1)
			    {
					for(i=0;i<num_thread;i++)
						args[i].abort = 1;
					continue;
				}
			case COM_EXIT:
				if(second == 1 && third == 1)
			    {
					for(i=0;i<num_thread;i++)
						args[i].abort = 1;
					for(i=0;i<num_thread;i++)
						pthread_join(threads[i],&value_ptr[i]);	
					
					return 0;
				}
				else
					return 0;
			default:
				continue;
		}
	}

	return 0;
}

void* test_mem(void *thread_arg)
{
	int i,j,k;
	unsigned int seed=28;
	char data[5] = {};
	char* addr = NULL;
	struct thread_args *arg;

	arg = (struct thread_args *)thread_arg;
	addr = arg->start_addr;

	fail = 0;
	srand(seed);
	data[0] = 0;
	data[1] = 0xFF;
	data[2] = 0x55;
	data[3] = 0xAA;
	data[4] = (char)rand();

	for(i=0;i<(arg->size);i++)
	{
		for(j=0;j<(arg->times);j++)
		{
			for(k=0;k<5;k++)
			{
				(*addr) = data[k];
				if((*addr) != data[k])
				{
					fail = 1;
					pthread_exit(&fail);
				}
			}
		}
		if(arg->abort == 1)
			pthread_exit(&fail);
		(arg->finished)++;
		addr++;
	}
	
	pthread_exit(&fail);
	return (void *)(&fail);
}

int get_command(void)
{
	int i;
	char tmp[20]={};
	int num=0;

	for(i=0;i<20;i++)                   /*命令数据结构初始化*/
		command.string[i] = '\0';
	command.value = 0;
	command.number = 0;
	
	scanf(" %s",tmp);
	
	if(!strcmp(tmp,"times"))
	{
		scanf(" %d",&num);
		if(num <= 0 || num > 1000000)
		{
			printf("测试次数参数非法!\n");
			command.value = 0;
			return -1;
		}
		command.number = num;
		command.value = COM_TIMES;
		return 0;
	}
	if(!strcmp(tmp,"thread"))
	{
		scanf(" %d",&num);
		if(num <= 0 || num > 10)
		{
			printf("线程个数参数非法!\n");
			command.value = 0;
			return -1;
		}
		command.number = num;
		command.value = COM_THREAD;
		return 0;
	}
	if(!strcmp(tmp,"go"))
	{
		command.value = COM_GO;
		return 0;
	}
	if(!strcmp(tmp,"status"))
	{
		command.value = COM_STATUS;
		return 0;
	}
	if(!strcmp(tmp,"abort"))
	{
		command.value = COM_ABORT;
		return 0;
	}
	if(!strcmp(tmp,"exit"))
	{
		command.value = COM_EXIT;
		return 0;
	}
	if(!strcmp(tmp,""))
	{
		command.value = 0;
		return -1;
	}

	printf("命令非法!\n");
	command.value = 0;
	return -1;
}
